#include "scene.h"
#include "editor.h"
#include "Scripting/scripting.h"

#include <cmath>
#include "Mathematics/Matrices/matrix4x4.h"

#include <ctime>
#include <iostream>
#include <SDL/SDL_image.h>
#include <anttweakbar.h>
using namespace std;

#undef main

CRenderer Renderer;
CScene Scene;
CWindow Window;

SDL_Event Event;

Matrix4x4 matWorld;

bool bEnd = false;

float fRotY = 0.0f, fRotX = 0.0f, fRotZ = 0.0f, fX = 0.0f, fY = 0.0f, fZ = -20.0f;

struct _Player
{
    float x, y, z;
    float fAngleVer, fAngleHor;
} Player;

struct _FPSCounter
{
    int nFPS;
    int nFrames;
    float fLastCountTime;

    void Init();
    void Update();
} FPSCounter;

void PreparePlayer();
void UpdatePlayer(Matrix4x4&, SDL_Event *pEvent);
void RotatePlayer(int relx, int rely);

int main()
{
	cout << "Started.\n";

	srand(time(NULL));

	Renderer.Init();
	Renderer.LinkWindow(&Window);
	Renderer.SetDisplayMode(800, 600, 32, SDL_RESIZABLE | SDL_OPENGL);

    Scene.SetRenderer(&Renderer);
    Scene.Load("data/abc.scene");

    ScrVariables.AutoInit();

    ScrLoadScript("data/abc.scene");
    ScrDoScript();

    for(Uint32 i = 0; i < ScrVariables.RenderObjectNames.size(); ++i)
    {
        Renderer.AddObject((*ScrVariables.pRenderObjects)[ScrVariables.RenderObjectNames[i]]);
    }

    ShaderProgram *pSPECIALSHADER = NULL, *pLIGHTSHADER = NULL;

    for(Uint32 i = 0; i < ScrVariables.ShaderNames.size(); ++i)
    {
        if(ScrVariables.ShaderNames[i] == "LIGHT_SHADER") pLIGHTSHADER = (*ScrVariables.pShaders)[ScrVariables.ShaderNames[i]];
        if(ScrVariables.ShaderNames[i] == "SPECIAL_SHADER") pSPECIALSHADER = (*ScrVariables.pShaders)[ScrVariables.ShaderNames[i]];
    }

    float fvLightPos[3] = {0.0f, 15.0f, 30.0f};
    pSPECIALSHADER->AddVector3("inLightPos", fvLightPos);
    pLIGHTSHADER->AddVector3("inLightPos", fvLightPos);

    /*TwInit(TW_OPENGL, NULL);
    TwWindowSize(800, 600);

    //---

    TwBar *Bar = TwNewBar("Menu");

    TwAddVarRW(Bar, "fX", TW_TYPE_FLOAT, &fX, " label='X' help='X position of the object' ");
    TwAddVarRW(Bar, "fY", TW_TYPE_FLOAT, &fY, " label='Y' help='Y position of the object' ");
    TwAddVarRW(Bar, "fZ", TW_TYPE_FLOAT, &fZ, " label='Z' help='Z position of the object' ");

    TwAddVarRW(Bar, "fRotX", TW_TYPE_FLOAT, &fRotX, " label='RotX' help='X rotation of the object' ");
    TwAddVarRW(Bar, "fRotY", TW_TYPE_FLOAT, &fRotY, " label='RotY' help='Y rotation of the object' ");
    TwAddVarRW(Bar, "fRotZ", TW_TYPE_FLOAT, &fRotZ, " label='RotZ' help='Z rotation of the object' ");

    TwDefine(" Menu help=\"These properties define the engine's behavior\" ");
    TwDefine(" GLOBAL help='Welcome!' ");*/

    //---

    Matrix4x4 &matView = *Renderer.GetMatViewPointer();

    PreparePlayer();

    FPSCounter.Init();

	while(!bEnd)
	{
		while(SDL_PollEvent(&Event))
		{
		    TwEventSDL(&Event, SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
			switch(Event.type)
			{
				case SDL_QUIT:
					bEnd = true;
					break;
				case SDL_KEYDOWN:
					if(Event.key.keysym.sym == SDLK_ESCAPE) bEnd = true;
					break;
                case SDL_KEYUP:
                    //TwRefreshBar(Bar);
                    break;
				case SDL_VIDEORESIZE:
					Renderer.ChangeDisplaySize(Event.resize.w, Event.resize.h);
					//TwWindowSize(Event.resize.w, Event.resize.h);
					break;
                case SDL_MOUSEMOTION:
                    RotatePlayer(Event.motion.x, Event.motion.y);
                    SDL_WarpMouse(400, 400);
                    break;
			}
		}
		/*Uint8 *keys = SDL_GetKeyState(NULL);
		if(keys[SDLK_LEFT]) fX -= 0.1f;
		if(keys[SDLK_RIGHT]) fX += 0.1f;
		if(keys[SDLK_DOWN]) fY -= 0.1f;
		if(keys[SDLK_UP]) fY += 0.1f;
		if(keys[SDLK_x]) fZ -= 0.1f;
		if(keys[SDLK_z]) fZ += 0.1f;*/

		UpdatePlayer(matView, &Event);

        Scene.Render();

        FPSCounter.Update();

        char chFPS[6] = {'\0'};
        itoa(FPSCounter.nFPS, chFPS, 10);

        SDL_WM_SetCaption(chFPS, NULL);

		//TwDraw();
		SDL_GL_SwapBuffers();
	}

	cout << "Exiting.\n";
	return 0;
}

void PreparePlayer()
{
    Player.x = Player.z = Player.fAngleVer = Player.fAngleHor = 0.0f;
    Player.y = 2.0f;
}

void UpdatePlayer(Matrix4x4 &matView, SDL_Event *pEvent)
{
    ///--events

    Uint8 *keys = SDL_GetKeyState(NULL);
    if(keys[SDLK_w])
    {
        Player.x += (float)(sin(ToRad(Player.fAngleVer))) * 0.1f;
        Player.z -= (float)(cos(ToRad(Player.fAngleVer))) * 0.1f;
    }
    if(keys[SDLK_s])
    {
        Player.x -= (float)(sin(ToRad(Player.fAngleVer))) * 0.1f;
        Player.z += (float)(cos(ToRad(Player.fAngleVer))) * 0.1f;
    }
    if(keys[SDLK_a])
    {
        Player.x += (float)(sin(ToRad(Player.fAngleVer-90.0f))) * 0.1f;
        Player.z -= (float)(cos(ToRad(Player.fAngleVer-90.0f))) * 0.1f;
    }
    if(keys[SDLK_d])
    {
        Player.x += (float)(sin(ToRad(Player.fAngleVer+90.0f))) * 0.1f;
        Player.z -= (float)(cos(ToRad(Player.fAngleVer+90.0f))) * 0.1f;
    }

    ///--events end

    matView.Identity();
    matView.Rotate(180.0f-Player.fAngleHor, Player.fAngleVer, 0.0f);
    matView.Translate(Player.x, -Player.y, Player.z);
}

void RotatePlayer(int xrel, int yrel)
{
    Player.fAngleVer += (((float)(xrel)-400.0f) * 0.1f);
    Player.fAngleHor += (((float)(yrel)-400.0f) * 0.1f);

    if(Player.fAngleHor>90.0f)Player.fAngleHor = 90.0f;
    if(Player.fAngleHor<-90.0f)Player.fAngleHor = -90.0f;
}

void _FPSCounter::Init()
{
    nFrames = 0;
    fLastCountTime = 0;
}

void _FPSCounter::Update()
{
    if(SDL_GetTicks() - fLastCountTime >= 1000)
    {
        nFPS = nFrames;
        fLastCountTime = SDL_GetTicks();
        nFrames = 0;
    }
    ++nFrames;
}
